package com.bdqn.demo.config;

import cn.hutool.json.JSONUtil;
import com.bdqn.demo.filter.JwtFilter;
import com.bdqn.demo.pojo.Resource;
import com.bdqn.demo.pojo.Role;
import com.bdqn.demo.pojo.User;
import com.bdqn.demo.service.ResourceService;
import com.bdqn.demo.utils.JwtUtils;
import com.bdqn.demo.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.Collection;
import java.util.List;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private JwtFilter jwtFilter;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(ahr ->
                ahr.requestMatchers("/login").permitAll()
                        .anyRequest().access(((authentication, object) -> {
                            String uri = object.getRequest().getRequestURI();
                            List<String> urls = resourceService.selectPermission().stream().map(Resource::getPermission).toList();
                            for (String url : urls) {
                                if (uri.startsWith(url)){
                                    if (!(authentication instanceof AnonymousAuthenticationToken))
                                        return new AuthorizationDecision(true);
                                }
                            }
                            List<Role> list = resourceService.selectByUrl(uri);
                            Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
                            for (Role role : list) {
                                if (authorities.contains(role.getName())) {
                                    return new AuthorizationDecision(true);
                                }
                            }
                            return new AuthorizationDecision(false);
                        }))
        );

        http.formLogin(login ->
                login.loginProcessingUrl("/login")
                        .successHandler(((request, response, authentication) -> {
                            response.setContentType("application/json;charset=utf-8");
                            User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
                            String token = JwtUtils.token(authentication);
                            redisTemplate.opsForValue().set(token, JSONUtil.toJsonStr(user));
                            response.getWriter().write(JSONUtil.toJsonStr(Result.ok("登录成功", token)));

                        }))
                        .failureHandler(((request, response, exception) -> {
                            response.setContentType("application/json;charset=utf-8");
                            response.getWriter().write(JSONUtil.toJsonStr(Result.fail(exception.getMessage())));
                        }))
        );

        http.csrf().disable();

        http.exceptionHandling(e -> e.accessDeniedHandler(((request, response, accessDeniedException) -> {
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(JSONUtil.toJsonStr(Result.fail(accessDeniedException.getMessage())));
        })));

        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web -> web.ignoring().requestMatchers("/image/**"));
    }

}
